<template>
  <div class="tree-table">
    <el-table
      v-if="origin.length > 0"
      :data="tableData"
      :row-key="id"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column
        v-for="(col, colIdx) of columns"
        :key="`${colIdx + 1}: ${col.prop || ''}`"
        :prop="col.prop"
        :label="col.label"
      >
        <template v-if="treeProps.includes(col.prop)" v-slot="{ row }">
          <child-item
            :label="row[col.prop] | statusText"
            :prop="col.prop"
            :value="row[col.prop]"
            :disabled="row._disabled || false"
            @on-change="changeValue(row, $event)"
          />
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import ChildItem from "./tree-table-item.vue";

import { formatTreeData, deepClone } from "@/libs/utils";
import i18n from "@/locale";

export default {
  name: "TreeTable",
  components: {
    ChildItem,
  },
  filters: {
    statusText(status) {
      switch (status) {
        case true:
          return i18n.t("TABLES.Opened");
        case false:
          return i18n.t("TABLES.Banned");
        default:
          return "";
      }
    },
  },
  props: {
    /** 原始的数组值 */
    origin: {
      type: Array,
      default: () => [],
    },
    /** 当前id标识 */
    id: {
      type: String,
      default: "id",
    },
    /** 父节点id标识 */
    pid: {
      type: String,
      default: "pid",
    },
    /** 渲染的列数据 */
    columns: {
      type: Array,
      default: () => [],
    },
    /** 需要渲染称树形结构的字段 */
    treeProps: {
      type: Array,
      default: () => [],
      validator(value) {
        if (!Array.isArray(value)) {
          return false;
        }
        if (value.some((val) => typeof val !== "string")) {
          return false;
        }
        return true;
      },
    },
  },
  data() {
    return {
      originData: [],
    };
  },
  computed: {
    /**
     * 依赖于原始数据的树形表格数据
     */
    tableData() {
      const tableData = formatTreeData(
        deepClone(this.originData),
        this.id,
        this.pid
      );

      return tableData || [];
    },
    /**
     * 根据treeProps判断选择的数据集合
     */
    checkedData() {
      const checkedData = {};

      this.treeProps.forEach((prop) => {
        const idList = this.originData
          .filter((item) => item[prop])
          .map((item) => item[this.id]);
        checkedData[prop] = idList;
      });

      return checkedData;
    },
  },
  watch: {
    checkedData: {
      deep: true,
      immediate: true,
      handler(newVal) {
        this.$emit("on-checked", newVal);
      },
    },
  },
  mounted() {
    this.setOrigin();
  },
  methods: {
    setOrigin() {
      this.$nextTick(() => {
        this.originData = [];
        const _origin = deepClone(this.origin);
        this.originData.push(..._origin);
      });
    },
    changeValue(rowItem, { prop, value }) {
      // find current-item
      const crtItem = this.originData.find(
        (item) => item[this.id] === rowItem[this.id]
      );

      if (crtItem) {
        /*
          1. 先设置自己的checked值
          2. 观察自己是否含有子元素: 有的话当前节点的子元素随着父元素一起变化
          3. 观察自己的父元素: 如果父元素中的子元素值都为true, 则父元素的checked值为true, 否则为false
        */
        this.$set(crtItem, prop, value);

        this.setChildrenValue(crtItem, { prop, value });

        this.setParentValue(crtItem, { prop, value });
      }
    },
    setChildrenValue(crtItem, { prop, value }) {
      const hasChildren = this.originData.some(
        (item) => item[this.pid] === crtItem[this.id]
      );
      if (hasChildren) {
        this.originData.forEach((cItem) => {
          if (cItem[this.pid] === crtItem[this.id]) {
            if (
              this.originData.some((item) => item[this.pid] === cItem[this.id])
            ) {
              this.setChildrenValue(cItem, { prop, value });
            }
            this.$set(cItem, prop, value);
          }
        });
      }
    },
    setParentValue(crtItem, { prop }) {
      // arguments: [crtItem, { prop, value }]
      const pItem = this.originData.find(
        (item) => item[this.id] === crtItem[this.pid]
      );
      if (pItem) {
        // const hasChildrenNode = false;
        const children = this.originData.filter(
            (item) => item[this.pid] === pItem[this.id]
          ),
          hasChildrenNode = children.some((item) => item[prop]);
        if (hasChildrenNode) {
          this.$set(pItem, prop, true);
        } else {
          this.$set(pItem, prop, false);
        }
        if (this.originData.some((item) => item[this.id] === pItem[this.pid])) {
          this.setParentValue(pItem, { prop });
        }
      }
    },
  },
};
</script>
